// generator.cpp

#include "includes.h"

/* generateBlackMoves() - This function takes a board and generates all of 
 *                        the possible legal moves that black could make 
 *                        and returns them as an a linked list */
std::list<Move> generateBlackMoves(board * inBoard)
{
  std::list<Move> moveList;

  debug(1, "entering generateBlackMoves()");

  generate_k_moves(inBoard, &moveList); //generate all black king moves
  generate_q_moves(inBoard, &moveList); //generate all black queen moves
  generate_b_moves(inBoard, &moveList); //generate all black bishop moves
  generate_n_moves(inBoard, &moveList); //generate all black night moves
  generate_r_moves(inBoard, &moveList); //generate all black rook moves
  generate_p_moves(inBoard, &moveList); //generate all black pawn moves

  debug(1, "exiting generateBlackMoves()");

  return moveList;
}

/* generateWhiteMoves() - This function takes a board and generates all of 
 *                        the possible legal moves that white could make 
 *                        and returns them as an a linked list */
std::list<Move> generateWhiteMoves(board * inBoard)
{
  std::list<Move> moveList;

  debug(1, "entering generateWhiteMoves()");

  generate_K_moves(inBoard, &moveList); //generate all white king moves
  generate_Q_moves(inBoard, &moveList); //generate all white queen moves
  generate_B_moves(inBoard, &moveList); //generate all white bishop moves
  generate_N_moves(inBoard, &moveList); //generate all white night moves
  generate_R_moves(inBoard, &moveList); //generate all white rook moves
  generate_P_moves(inBoard, &moveList); //generate all white pawn moves

  debug(1, "exiting generateWhiteMoves()");

  return moveList;
}

int generate_k_moves(board * inBoard, std::list<Move> * moveList)
{
  unsigned int original = inBoard->k;
  unsigned int move = 0; 

  debug(1, "entering generate_k_moves");
  
  move = move_n(original);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_front(Move(original, move));
  
  move = move_ne(original);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_front(Move(original, move));

  move = move_nw(original);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_front(Move(original, move));

  move = move_s(original);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_front(Move(original, move));

  move = move_se(original);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_front(Move(original, move));

  move = move_sw(original);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_front(Move(original, move));

  move = move_e(original);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_front(Move(original, move));

  move = move_w(original);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_front(Move(original, move));

  debug(1, "exiting generate_k_moves()");

  return 0;
}

int generate_q_moves(board * inBoard, std::list<Move> * moveList)
{
  unsigned int move = 0;
	std::list<unsigned int> pieceList = listPieces(inBoard->q);
  std::list<unsigned int>::const_iterator pieceIterator = pieceList.begin();

  debug(1, "entering generate_q_moves()");

	for (pieceIterator = pieceList.begin(); pieceIterator != pieceList.end();  
			 pieceIterator++)
  {
		// north first
		move = move_n(*pieceIterator);
		while(move && !collideBlack(inBoard, move))
		{
			moveList->push_front(Move(*pieceIterator, move));
			if (collideWhite(inBoard, move))
				break;
			else
				move = move_n(move);
		}

		// south 
		move = move_s(*pieceIterator);
		while(move && !collideBlack(inBoard, move))
		{
			moveList->push_front(Move(*pieceIterator, move));
			if (collideWhite(inBoard, move))
				break;
			else
				move = move_s(move);
		}

		// now east
		move = move_e(*pieceIterator);
		while(move && !collideBlack(inBoard, move))
		{
			moveList->push_front(Move(*pieceIterator, move));
			if (collideWhite(inBoard, move))
				break;
			else
				move = move_e(move);
		}

		// west 
		move = move_w(*pieceIterator);
		while(move && !collideBlack(inBoard, move))
		{
			moveList->push_front(Move(*pieceIterator, move));
			if (collideWhite(inBoard, move))
				break;
			else
				move = move_w(move);
		}

		// ne 
		move = move_ne(*pieceIterator);
		while(move && !collideBlack(inBoard, move))
		{
			moveList->push_front(Move(*pieceIterator, move));
			if (collideWhite(inBoard, move))
				break;
			else
				move = move_ne(move);
		}

		// nw 
		move = move_nw(*pieceIterator);
		while(move && !collideBlack(inBoard, move))
		{
			moveList->push_front(Move(*pieceIterator, move));
			if (collideWhite(inBoard, move))
				break;
			else
				move = move_nw(move);
		}

		// now se
		move = move_se(*pieceIterator);
		while(move && !collideBlack(inBoard, move))
		{
			moveList->push_front(Move(*pieceIterator, move));
			if (collideWhite(inBoard, move))
				break;
			else
				move = move_se(move);
		}

		// sw last
		move = move_sw(*pieceIterator);
		while(move && !collideBlack(inBoard, move))
		{
			moveList->push_front(Move(*pieceIterator, move));
			if (collideWhite(inBoard, move))
				break;
			else
				move = move_sw(move);
		}
	}

  debug(1, "exiting generate_q_moves()");

  return 0;
}

int generate_b_moves(board * inBoard, std::list<Move> * moveList)
{
  unsigned int original = inBoard->b;
  unsigned int move = 0;

  debug(1, "entering generate_b_moves()");

  // ne first
  move = move_ne(original);
  while(move && !collideBlack(inBoard, move))
  {
    moveList->push_front(Move(original, move));
    if (collideWhite(inBoard, move))
      break;
    else
      move = move_ne(move);
  }

  // nw next
  move = move_nw(original);
  while(move && !collideBlack(inBoard, move))
  {
    moveList->push_front(Move(original, move));
    if (collideWhite(inBoard, move))
      break;
    else
      move = move_nw(move);
  }

  // now se
  move = move_se(original);
  while(move && !collideBlack(inBoard, move))
  {
    moveList->push_front(Move(original, move));
    if (collideWhite(inBoard, move))
      break;
    else
      move = move_se(move);
  }

  // sw last
  move = move_sw(original);
  while(move && !collideBlack(inBoard, move))
  {
    moveList->push_front(Move(original, move));
    if (collideWhite(inBoard, move))
      break;
    else
      move = move_sw(move);
  }

  debug(1, "exiting generate_b_moves()");

  return 0;
}

int generate_n_moves(board * inBoard, std::list<Move> * moveList)
{
  unsigned int original = inBoard->n;
  unsigned int move = 0;

  debug(1, "entering generate_n_moves()");

  // north first
  move = move_n(original);
  move = move_n(move); 
  move = move_e(move);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_front(Move(original, move));
  move = move_w(move);
  move = move_w(move);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_front(Move(original, move));

  // south next
  move = move_s(original);
  move = move_s(move); 
  move = move_e(move);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_front(Move(original, move));
  move = move_w(move);
  move = move_w(move);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_front(Move(original, move));

  // now east
  move = move_e(original);
  move = move_e(move); 
  move = move_n(move);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_front(Move(original, move));
  move = move_s(move);
  move = move_s(move);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_front(Move(original, move));

  // west last
  move = move_w(original);
  move = move_w(move); 
  move = move_n(move);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_front(Move(original, move));
  move = move_s(move);
  move = move_s(move);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_front(Move(original, move));

  debug(1, "exiting generate_n_moves()");

  return 0;
}

int generate_r_moves(board * inBoard, std::list<Move> * moveList)
{
  unsigned int original = inBoard->r;
  unsigned int move = 0;

  debug(1, "entering generate_r_moves()");

  // north first
  move = move_n(original);
  while(move && !collideBlack(inBoard, move))
  {
    moveList->push_front(Move(original, move));
    if (collideWhite(inBoard, move))
      break;
    else
      move = move_n(move);
  }

  // south next
  move = move_s(original);
  while(move && !collideBlack(inBoard, move))
  {
    moveList->push_front(Move(original, move));
    if (collideWhite(inBoard, move))
      break;
    else
      move = move_s(move);
  }

  // now east
  move = move_e(original);
  while(move && !collideBlack(inBoard, move))
  {
    moveList->push_front(Move(original, move));
    if (collideWhite(inBoard, move))
      break;
    else
      move = move_e(move);
  }

  // west last
  move = move_w(original);
  while(move && !collideBlack(inBoard, move))
  {
    moveList->push_front(Move(original, move));
    if (collideWhite(inBoard, move))
      break;
    else
      move = move_w(move);
  }

  debug(1, "exiting generate_r_moves()");

  return 0;
}

int generate_p_moves(board * inBoard, std::list<Move> * moveList)
{
  unsigned int original = inBoard->p;
  unsigned int move = 0;
  std::list<unsigned int> pieceList = listPieces(original);
  std::list<unsigned int>::const_iterator pieceIterator = pieceList.begin();

  debug(1, "entering generate_p_moves()");

	for (pieceIterator = pieceList.begin(); pieceIterator != pieceList.end(); 
				 pieceIterator++)
  {
    move = move_s(*pieceIterator);
    if (move && !collideBlack(inBoard, move) && !collideWhite(inBoard, move)) 
      moveList->push_front(Move(*pieceIterator, move));

    move = move_se(*pieceIterator);
    if (move && !collideBlack(inBoard, move) && collideWhite(inBoard, move)) 
      moveList->push_front(Move(*pieceIterator, move));

    move = move_sw(*pieceIterator);
    if (move && !collideBlack(inBoard, move) && collideWhite(inBoard, move)) 
      moveList->push_front(Move(*pieceIterator, move));  
  }

  debug(1, "exiting generate_p_moves()");

  return 0;
}

int generate_K_moves(board * inBoard, std::list<Move> * moveList)
{
	unsigned int original = inBoard->K;
  unsigned int move = 0; 

  debug(1, "entering generate_K_moves()");
  
  move = move_n(original);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_front(Move(original, move));

  move = move_ne(original);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_front(Move(original, move));

  move = move_nw(original);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_front(Move(original, move));

  move = move_s(original);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_front(Move(original, move));

  move = move_se(original);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_front(Move(original, move));

  move = move_sw(original);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_front(Move(original, move));

  move = move_e(original);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_front(Move(original, move));

  move = move_w(original);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_front(Move(original, move));

  debug(1, "exiting generate_K_moves()");

  return 0;
}

int generate_Q_moves(board * inBoard, std::list<Move> * moveList)
{
  unsigned int move = 0;
  std::list<unsigned int> pieceList = listPieces(inBoard->Q);
  std::list<unsigned int>::const_iterator pieceIterator = pieceList.begin();

  debug(1, "entering generate_Q_moves()");

	for (pieceIterator = pieceList.begin(); pieceIterator != pieceList.end(); 
			 pieceIterator++)
  {
		// north first
		move = move_n(*pieceIterator);
		while(move && !collideWhite(inBoard, move))
		{
			moveList->push_front(Move(*pieceIterator, move));
			if (collideBlack(inBoard, move))
				break;
			else
				move = move_n(move);
		}

		// south 
		move = move_s(*pieceIterator);
		while(move && !collideWhite(inBoard, move))
		{
			moveList->push_front(Move(*pieceIterator, move));
			if (collideBlack(inBoard, move))
				break;
			else
				move = move_s(move);
		}

		// now east
		move = move_e(*pieceIterator);
		while(move && !collideWhite(inBoard, move))
		{
			moveList->push_front(Move(*pieceIterator, move));
			if (collideBlack(inBoard, move))
				break;
			else
				move = move_e(move);
		}

		// west 
		move = move_w(*pieceIterator);
		while(move && !collideWhite(inBoard, move))
		{
			moveList->push_front(Move(*pieceIterator, move));
			if (collideBlack(inBoard, move))
				break;
			else
				move = move_w(move);
		}

		// ne 
		move = move_ne(*pieceIterator);
		while(move && !collideWhite(inBoard, move))
		{
			moveList->push_front(Move(*pieceIterator, move));
			if (collideBlack(inBoard, move))
				break;
			else
				move = move_ne(move);
		}

		// nw 
		move = move_nw(*pieceIterator);
		while(move && !collideWhite(inBoard, move))
		{
			moveList->push_front(Move(*pieceIterator, move));
			if (collideBlack(inBoard, move))
				break;
			else
				move = move_nw(move);
		}

		// now se
		move = move_se(*pieceIterator);
		while(move && !collideWhite(inBoard, move))
		{
			moveList->push_front(Move(*pieceIterator, move));
			if (collideBlack(inBoard, move))
				break;
			else
				move = move_se(move);
		}

		// sw last
		move = move_sw(*pieceIterator);
		while(move && !collideWhite(inBoard, move))
		{
			moveList->push_front(Move(*pieceIterator, move));
			if (collideBlack(inBoard, move))
				break;
			else
				move = move_sw(move);
		}
	}

  debug(1, "exiting generate_Q_moves()");

  return 0;
}

int generate_B_moves(board * inBoard, std::list<Move> * moveList)
{
  unsigned int original = inBoard->B;
  unsigned int move = 0;

  debug(1, "entering generate_B_moves()");

  // ne first
  move = move_ne(original);
  while(move && !collideWhite(inBoard, move))
  {
    moveList->push_front(Move(original, move));
    if (collideBlack(inBoard, move))
      break;
    else
      move = move_ne(move);
  }

  // nw next
  move = move_nw(original);
  while(move && !collideWhite(inBoard, move))
  {
    moveList->push_front(Move(original, move));
    if (collideBlack(inBoard, move))
      break;
    else
      move = move_nw(move);
  }

  // now se
  move = move_se(original);
  while(move && !collideWhite(inBoard, move))
  {
    moveList->push_front(Move(original, move));
    if (collideBlack(inBoard, move))
      break;
    else
      move = move_se(move);
  }

  // sw last
  move = move_sw(original);
  while(move && !collideWhite(inBoard, move))
  {
    moveList->push_front(Move(original, move));
    if (collideBlack(inBoard, move))
      break;
    else
      move = move_sw(move);
  }

  debug(1, "exiting generate_B_moves()");

  return 0;
}

int generate_N_moves(board * inBoard, std::list<Move> * moveList)
{
  unsigned int original = inBoard->N;
  unsigned int move = 0;

  debug(1, "entering generate_N_moves()");

  // north first
  move = move_n(original);
  move = move_n(move); 
  move = move_e(move);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_front(Move(original, move));
  move = move_w(move);
  move = move_w(move);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_front(Move(original, move));

  // south next
  move = move_s(original);
  move = move_s(move); 
  move = move_e(move);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_front(Move(original, move));
  move = move_w(move);
  move = move_w(move);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_front(Move(original, move));

  // now east
  move = move_e(original);
  move = move_e(move); 
  move = move_n(move);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_front(Move(original, move));
  move = move_s(move);
  move = move_s(move);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_front(Move(original, move));

  // west last
  move = move_w(original);
  move = move_w(move); 
  move = move_n(move);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_front(Move(original, move));
  move = move_s(move);
  move = move_s(move);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_front(Move(original, move));  

  debug(1, "exiting generate_N_moves()");

  return 0;
}

int generate_R_moves(board * inBoard, std::list<Move> * moveList)
{
  unsigned int original = inBoard->R;
  unsigned int move = 0;

  debug(1, "entering generate_R_moves()");

  // north first
  move = move_n(original);
  while(move && !collideWhite(inBoard, move))
  {
    moveList->push_front(Move(original, move));
    if (collideBlack(inBoard, move))
      break;
    else
      move = move_n(move);
  }

  // south next
  move = move_s(original);
  while(move && !collideWhite(inBoard, move))
  {
    moveList->push_front(Move(original, move));
    if (collideBlack(inBoard, move))
      break;
    else
      move = move_s(move);
  }

  // now east
  move = move_e(original);
  while(move && !collideWhite(inBoard, move))
  {
    moveList->push_front(Move(original, move));
    if (collideBlack(inBoard, move))
      break;
    else
      move = move_e(move);
  }

  // west last
  move = move_w(original);
  while(move && !collideWhite(inBoard, move))
  {
    moveList->push_front(Move(original, move));
    if (collideBlack(inBoard, move))
      break;
    else
      move = move_w(move);
  }

  debug(1, "exiting generate_R_moves()");

  return 0;
}

int generate_P_moves(board * inBoard, std::list<Move> * moveList)
{
  unsigned int original = inBoard->P;
  unsigned int move = 0;
  std::list<unsigned int> pieceList = listPieces(original);
  std::list<unsigned int>::const_iterator pieceIterator = pieceList.begin();

  debug(1, "entering generate_P_moves()");

	for (pieceIterator = pieceList.begin(); pieceIterator != pieceList.end(); 
			 pieceIterator++)
  {
    move = move_n(*pieceIterator);
    if (move && !collideWhite(inBoard, move) && !collideBlack(inBoard, move)) 
      moveList->push_front(Move(*pieceIterator, move));

    move = move_ne(*pieceIterator);
    if (move && !collideWhite(inBoard, move) && collideBlack(inBoard, move)) 
      moveList->push_front(Move(*pieceIterator, move));

    move = move_nw(*pieceIterator);
    if (move && !collideWhite(inBoard, move) && collideBlack(inBoard, move)) 
      moveList->push_front(Move(*pieceIterator, move)); 
  }

  debug(1, "exiting generate_P_moves()");
  
  return 0;
}

/* for this class of functions, if it would not constitute moving off of the
 * board, we return the bitboard representing the new position. If it would
 * constitute moving off of the board, we return 0
 * */
unsigned int move_n(unsigned int mask)
{
  debug(1, "entering move_n()");

  if (mask & (A6 | B6 | C6 | D6 | E6 ))
    return 0;
  else
    return mask << 5; 

  debug(1, "exiting move_n()");
}

unsigned int move_s(unsigned int mask)
{
  debug(1, "entering move_s()");

  if (mask & (A1 | B1 | C1 | D1 | E1))
    return 0;
  else
    return mask >> 5; 

  debug(1, "exiting move_s()");
}

unsigned int move_e(unsigned int mask)
{
  debug(1, "entering move_e()");

  if (mask & (E6 | E5 | E4 | E3 | E2 | E1))
    return 0;
  else
    return mask >> 1;

  debug(1, "exiting move_e()");
}

unsigned int move_w(unsigned int mask)
{
  debug(1, "entering move_w()");

  if (mask & (A6 | A5 | A4 | A3 | A2 | A1))
    return 0;
  else
    return mask << 1;

  debug(1, "exiting move_w()");
}

unsigned int move_ne(unsigned int mask)
{
  debug(1, "entering move_ne()");

  if (mask & (A6 | B6 | C6 | D6 | E6 | E5 | E4 | E3 | E2 | E1))
    return 0;
  else
    return mask << 4;

  debug(1, "exiting move_ne()");
}

unsigned int move_nw(unsigned int mask)
{
  debug(1, "entering move_nw()");

  if (mask & (A1 | A2 | A3 | A4 | A5 | A6 | B6 | C6 | D6 | E6))
    return 0;
  else
    return mask << 6;

  debug(1, "exiting move_nw()");
}

unsigned int move_se(unsigned int mask)
{
  debug(1, "entering move_se()");

  if (mask & (A1 | B1 | C1 | D1 | E1 | E2 | E3 | E4 | E5 | E6)) 
    return 0;
  else
    return mask >> 6;

  debug(1, "exiting move_se()");
}

unsigned int move_sw(unsigned int mask)
{
  debug(1, "entering move_sw()");

  if (mask & (A6 | A5 | A4 | A3 | A2 | A1 | B1 | C1 | D1 | E1)) 
    return 0;
  else
    return mask >> 4;

  debug(1, "exiting move_sw()");
}

